#include <iostream>
#include <cstdlib>
#include <signal.h>
#include <physfs.h>

#include "storage.h"
#include "enet/enet.h"
#include "utils/time.h"
#include "utils/logger.h"
#include "utils/processorutils.h"
#include "utils/timer.h"
#include "common/resourcemanager.h"
#include "common/configuration.h"
#include "common/defines.h"
#include "common/manaserv_protocol.h"
#include "net/bandwidth.h"

using utils::Logger;

bool gServerRunning = true;
static std::string gStatFile = std::string();
Storage *storage;
BandwidthMonitor *gBandwidth;
//semacam bandwidth monitor ga terlalu penting,
//harusnya singleton dan tidak tergantung netcomputer
//nama harus persis sama

static void closeGracefully(int)
{
    gServerRunning = false;
}

static void initialize()
{
    // Used to close via process signals
#if (defined __USE_UNIX98 || defined __FreeBSD__)
    signal(SIGQUIT, closeGracefully);
#endif
    signal(SIGINT, closeGracefully);
    signal(SIGTERM, closeGracefully);

    std::string logFile = Configuration::getValue("log_accountServerFile",
                                                  "accountserver.log");

    // Initialize PhysicsFS
    PHYSFS_init("");

    // Initialize the logger.
    Logger::setLogFile(logFile, true);

    // Write the messages to both the screen and the log file.
    Logger::setTeeMode(
                      Configuration::getBoolValue("log_accountToStandardOutput",
                                                  true));
    LOG_INFO("Using log file: " << logFile);

    // Indicate in which file the statistics are put.
    gStatFile = Configuration::getValue("log_statisticsFile",
                                        "accountserver.stat");

    LOG_INFO("Using statistics file: " << gStatFile);

    // Set up the options related to log rotation.
    Logger::enableLogRotation(Configuration::getBoolValue("log_enableRotation",
                                                          false));
    Logger::setMaxLogfileSize(Configuration::getValue("log_maxFileSize",
                                                      1024));
    Logger::setSwitchLogEachDay(Configuration::getBoolValue("log_perDay",
                                                            false));
    ResourceManager::initialize(); // soal load-load file, physfs

    // Open database
    try
    {
        storage = new Storage;
        storage->open();
    }
    catch (std::string &error)
    {
        LOG_FATAL("Error opening the database: " << error);
        exit(EXIT_DB_EXCEPTION);
    }

//    // --- Initialize the managers
//    stringFilter = new utils::StringFilter;  // The slang's and double quotes filter.
//    chatChannelManager = new ChatChannelManager;
//    guildManager = new GuildManager;
//    postalManager = new PostManager;
    gBandwidth = new BandwidthMonitor;
//
//    // --- Initialize the global handlers
//    // FIXME: Make the global handlers global vars or part of a bigger
//    // singleton or a local variable in the event-loop
//    chatHandler = new ChatHandler;
//
    // --- Initialize enet.
    if (enet_initialize() != 0) //nedd enet.a, winmm.a and win32.a, urutan hrs enet duluan
    {
        LOG_FATAL("An error occurred while initializing ENet");
        exit(EXIT_NET_EXCEPTION);
    }

    utils::processor::init(); // buat ngecek little endia atau bukan
    std::srand( time(NULL) );
}

static void deinitialize()
{
    Configuration::deinitialize(); // yg options, ga efek

    // Destroy message handlers.
    //AccountClientHandler::deinitialize();
    //GameServerHandler::deinitialize();

    // Quit ENet
    enet_deinitialize();

    //delete chatHandler;

    // Destroy Managers
    //delete stringFilter;
    //delete chatChannelManager;
    //delete guildManager;
    //delete postalManager;
    delete gBandwidth;

    // Get rid of persistent data storage
    delete storage;

    PHYSFS_deinit();
}

static void initializeConfiguration()
{
    std::string configPath = "manaserv.xml";

    if (Configuration::initialize(configPath) == false)
    {
        LOG_FATAL("Refusing to run without configuration!" << std::endl
        << "Invalid config path: " << configPath << ".");
        exit(EXIT_CONFIG_NOT_FOUND);
    }

    LOG_INFO("Using config file: " << configPath);

    // Check inter-server password.
    if (Configuration::getValue("net_password", std::string()).empty())
    {
        LOG_FATAL("SECURITY WARNING: 'net_password' not set!");
        exit(EXIT_BAD_CONFIG_PARAMETER);
    }
}

int main()
{
    int port = 9601;

    Logger::setVerbosity(Logger::Debug);

    initializeConfiguration();
    initialize();

    LOG_INFO("Manaserv Protocol version " << ManaServ::PROTOCOL_VERSION
             << ", Enet version " << ENET_VERSION_MAJOR << "."
             << ENET_VERSION_MINOR << "." << ENET_VERSION_PATCH);

    Logger::Level verbosity = static_cast<Logger::Level>(
        Configuration::getValue("log_accountServerLogLevel",
        Logger::Debug) );

    Logger::setVerbosity(verbosity);

    std::string accountHost = Configuration::getValue("net_accountHost",
                                                      "localhost");
    std::string chatHost = Configuration::getValue("net_chatHost",
                                                   "localhost");

    port = Configuration::getValue("net_accountListenToClientPort",
                                   9601);
    int accountGamePort = Configuration::getValue("net_accountListenToGamePort",
                                                  port + 1);
    int chatClientPort = Configuration::getValue("net_chatListenToClientPort",
                                                 port + 2);

    // Dump statistics every 10 seconds.
    utils::Timer statTimer(10000);
    // Check for expired bans every 30 seconds
    utils::Timer banTimer(30000);

    deinitialize();

    return 0;
}
